export class PCMRecorder {
  private recorder: WechatMiniprogram.RecorderManager
  private base64Chunks: string[]
  private ctx: WechatMiniprogram.CanvasContext | null
  private canvasWidth: number
  private canvasHeight: number
  private _lastWaveDraw: number
  private onCompleteCallback?: (base64: string) => void  // 外部回调

  constructor(onComplete?: (base64: string) => void) {
    // 初始化属性
    this.recorder = wx.getRecorderManager();
    this.base64Chunks = [];
    this.ctx = null;
    this.canvasWidth = 0;
    this.canvasHeight = 0;
    this._lastWaveDraw = 0;
    this.onCompleteCallback = onComplete || undefined
  }

  /** 初始化 Canvas */
  initCanvas(canvasId: string, width: number, height: number, scope: any) {
    this.ctx = wx.createCanvasContext(canvasId, scope)
    this.canvasWidth = width
    this.canvasHeight = height
  }
  /** 开始录音并绑定帧回调 */
  start() {
    this.base64Chunks = []
    this._lastWaveDraw = 0
    this.recorder.onFrameRecorded((res) => {
      const pcmBuffer = res.frameBuffer
      const base64Chunk = wx.arrayBufferToBase64(pcmBuffer as ArrayBuffer)
      this.base64Chunks.push(base64Chunk)
      // 绘制波形
      this._drawFrame(pcmBuffer)
    })
    this.recorder.onStop((res) => {
      this._handleStop(res.tempFilePath)
    })
    this.recorder.start({
      duration: 30000, //录音的时长
      sampleRate: 16000, // 16kHz
      numberOfChannels: 1, // 单声道
      format: 'wav' as any, //音频格式
      frameSize: 1,       // 指定帧大小，单位kb
    })
  }
  /** 停止录音 */
  stop() {
    this.recorder.stop()
  }
  /** 内部 stop 处理 */
  private _handleStop(tempFilePath: string) {
    // 清空波形
    if (this.ctx) {
      this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
      this.ctx.draw(true)
    }
    // // 播放
    // const innerAudioContext = wx.createInnerAudioContext()
    // innerAudioContext.src = res.tempFilePath
    // innerAudioContext.play()
    const fsm = wx.getFileSystemManager()
    fsm.readFile({
      filePath: tempFilePath,
      success: (fileRes) => {
        const finalBase64 = wx.arrayBufferToBase64(fileRes.data as ArrayBuffer)
        // ✅ 无论是自动停还是手动停，都走这个回调
        if (this.onCompleteCallback) {
          this.onCompleteCallback(finalBase64)
        }
        // const bytes = new Uint8Array(fileRes.data as any)
        // let finalBase64
        // if (bytes[0] === 0x1a && bytes[1] === 0x45 && bytes[2] === 0xdf && bytes[3] === 0xa3) {
        //   // 模拟器 WebM/Opus，直接发送
        //   finalBase64 = wx.arrayBufferToBase64(fileRes.data as any)
        // } else {
        //   // 真机 PCM，加 WAV 头
        //   const wavBuffer = encodeWAV(fileRes.data as any, 16000, 1)
        //   finalBase64 = wx.arrayBufferToBase64(wavBuffer)
        // }
        // resolve(finalBase64)
        // return
      },
    })
  }

  /** 获取实时分片 */
  getChunks(): string[] {
    return this.base64Chunks
  }

  /** 内部：绘制波形 */
  private _drawFrame(buffer: ArrayBuffer) {
    if (!this.ctx) return
    const now = Date.now()
    if (now - this._lastWaveDraw < 30) return
    this._lastWaveDraw = now
    const int16 = new Int16Array(buffer)
    if (!int16.length) return
    const float32 = new Float32Array(int16.length)
    for (let i = 0; i < int16.length; i++) {
      float32[i] = int16[i] / 32768
    }
    const barWidth = 3, gap = 2
    const maxBars = Math.floor(this.canvasWidth / (barWidth + gap)) || 40
    const step = Math.floor(float32.length / maxBars) || 1
    const sampled: number[] = []
    for (let i = 0; i < maxBars; i++) {
      let sumSq = 0
      for (let j = 0; j < step; j++) {
        const idx = i * step + j
        if (idx < float32.length) {
          sumSq += float32[idx] * float32[idx]
        }
      }
      const rms = Math.sqrt(sumSq / step)
      sampled.push(rms)
    }
    // 指数压缩增强视觉差异
    let prev = 0.5
    const normalized = sampled.map(v => {
      let n = 0.6 * prev + 0.4 * v
      n *= 0.7 + Math.random() * 0.6
      prev = n
      return Math.min(n, 1)
    })
    this._drawWaveformMiniProgram(this.ctx, this.canvasWidth, this.canvasHeight, normalized)
  }
  /** 内部：实际绘制 */
  private _drawWaveformMiniProgram(ctx: WechatMiniprogram.CanvasContext, width: number, height: number, data: number[]) {
    ctx.setFillStyle('#00ADAD')
    ctx.fillRect(0, 0, width, height)
    const barWidth = 3, gap = 2
    ctx.setFillStyle('#fff')
    let x = 0
    const mid = height / 2
    for (let i = 0; i < data.length; i++) {
      const v = data[i]
      const barHeight = v * mid
      ctx.fillRect(x, mid - barHeight, barWidth, barHeight * 2)
      x += barWidth + gap
      if (x > width) break
    }
    ctx.draw(false)
  }
}

function encodeWAV(pcmData: ArrayBuffer, sampleRate = 16000, numChannels = 1): ArrayBuffer {
  const pcmView = new DataView(pcmData)
  const numSamples = Math.floor(pcmData.byteLength / 2) // 16bit PCM 样本数
  const buffer = new ArrayBuffer(44 + numSamples * 2)
  const view = new DataView(buffer)

  // 写 WAV 头
  writeString(view, 0, 'RIFF')
  view.setUint32(4, 36 + numSamples * 2, true)
  writeString(view, 8, 'WAVE')
  writeString(view, 12, 'fmt ')
  view.setUint32(16, 16, true)
  view.setUint16(20, 1, true)
  view.setUint16(22, numChannels, true)
  view.setUint32(24, sampleRate, true)
  view.setUint32(28, sampleRate * numChannels * 2, true)
  view.setUint16(32, numChannels * 2, true)
  view.setUint16(34, 16, true)
  writeString(view, 36, 'data')
  view.setUint32(40, numSamples * 2, true)

  // 写 PCM 数据（安全版）
  for (let i = 0; i < numSamples; i++) {
    // 防止越界
    const offset = i * 2
    if (offset + 1 < pcmData.byteLength) {
      const sample = pcmView.getInt16(offset, true)
      view.setInt16(44 + offset, sample, true)
    }
  }
  return buffer
}
function writeString(view: DataView, offset: number, str: string) {
  for (let i = 0; i < str.length; i++) {
    view.setUint8(offset + i, str.charCodeAt(i))
  }
}
